Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Release 0.16 - alignment with consolidated tooling wrt chain making #501

Conversation

benjaminbollen
Copy link
Contributor

@benjaminbollen benjaminbollen commented Feb 19, 2017

After consolidation of eris-cm and eris-pm into eris tooling; some technical debt had to be resolved. This PR is necessary for this re-alignment in eris https://github.com/eris-ltd/eris/pull/1235 to complete.

checklist:

  • clean up eris-db dependencies of permissions; merged in Cleanup: introduce word256 and remove dependency on tendermint/go-common #499
  • permissions utility to convert map[string]int into permissions type
  • genesis: define constructors for Genesis types to contain explicit dependency on tendermint/go-crypto into tooling; enabling us to inject our own crypto package without coordination with tooling.
  • genesis: introduce GenesisPrivateValidtor as an intermediary step to removing priv_validator logic from the stack
  • genesis: provide genesis.GenerateGenesisFileBytes(chainName, []*GenesisAccount, []*GenesisValidator) for tooling
  • final review

Copy link
Contributor

@silasdavis silasdavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good in terms of structure which is definitely an improvement.

I take issue with the over-defensive use of cloning everything. Often you are cloning values that are copied on the call stack anyway. Where you are dealing with pointers it ought really be part of the contract that we are not handed mutable bytes by the implementer. In terms of the actual implementations we can see that we are not passed mutable bytes and we know we are not mutating them. So I'm not sure the extra complexity is justified. Plus it signals that we need to be cloning we I am not convinced we do. Though perhaps I am missing something.


// TODO: assert valid accounts and validators
// TODO: [ben] expose setting global permissions
globalPermissions := ptypes.DefaultAccountPermissions.Clone()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary DefaultAccountPermissions is a struct value so it's copied on assignment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but is a struct AccountPermissions of a struct BasePermissions and a slice of strings; I believe - but not sure - that the struct BasePermissions is treated as a pointer essentially; but definitely the Roles []string is an effective pointer;

secondly, genesis is currently constructed with Params as a pointer to a GenesisParams which is a pointer to an AccountPermissions; I dont particularly like this construction; but I didnt want to end up with a GenesisDoc that didnt own its own data;

Arguably this does read very defensive

Copy link
Contributor

@silasdavis silasdavis Feb 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner struct is just another value, the memory is copied in a single pass. See: https://play.golang.org/p/Ut_7gZ3TyJ

Yeah the slice does give you mutable access. But this is go, I think we need to choose our battles. I'd rather we were passing immutable sequences of values but we're not. And in the event we are not writing back to the roles, and that would be a weird thing to do.

@@ -28,6 +28,25 @@ func GenerateKnown(chainID, accountsPathCSV, validatorsPathCSV string) (string,
}

//------------------------------------------------------------------------------------
// interface functions that are consumed by monax tooling

func GenerateGenesisFileBytes(chainName string, genesisAccounts []*GenesisAccount,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to other comment, if it's convenient to pass genesisAccounts []GenesisAccount then we could probably get away without a clone... (though we do have pointers from GenesisAccount to AccountPermissions, but I don't think we accidentally mutate here)

Copy link
Contributor Author

@benjaminbollen benjaminbollen Feb 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in tooling there is a usage of passing slices of pointers; which is justified there because they are passed around a lot during construction;

this is why i deliberately gave tooling an interface that respects the [ ]*T; but GenesisDoc is constructed with [ ]T and once GenesisDoc is constructed changing the original argument T should not affect the GenesisDoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought that might be the case. Makes sense.

genesis/maker.go Outdated
switch keyType {
case "ed25519":
// TODO: [ben] functionality and checks need to be inherit in the type
if len(publicKeyBytes) != 32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather replace all magic number references with named constants

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but tendermint/go-crypto/pub_key.go does not have this definition; and while I agree with you. I prefer to hold off making that definition until (very soon) we make eris-db/crypto

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just name it in the same file, let's not make the perfect an enemy of the good.

genesis/maker.go Outdated
len(publicKeyBytes))
}
// ed25519 has type byte 0x01
typedPublicKeyBytes = make([]byte, 33)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise would prefer publicKeyLength + 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, on the same page, but without a const, 32+1 is a bit weird

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, which is why you should introduce the constant. In the same file if necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im ok with introducing the constants and moving them later

genesis/maker.go Outdated
// prepend type byte to public key
typedPublicKeyBytes = append([]byte{crypto.PubKeyTypeEd25519}, publicKeyBytes...)
case "secp256k1":
if len(publicKeyBytes) != 64 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again

genesis/maker.go Outdated
len(publicKeyBytes))
}
// secp256k1 has type byte 0x02
typedPublicKeyBytes = make([]byte, 65)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

genesis/types.go Outdated
}
// clone the public key by writing and reading over go-wire serialisation
// TODO! write unit test to see whether this is correct
publicKeyClone, err := crypto.PubKeyFromBytes(genesisValidator.PubKey.Bytes())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how this is sort of defensive. But I wonder if it is a step too far. Ultimately we have to trust that we are not being handed internal bytes slice that we might mutate. We can see for sure that we are not being handed a reference to internal bytes as it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a Clone in general is very good practice, because it allows you to make it explicit when you're copying data; and as a result avoid copying it when you don't have to.

Here again Clone is introduced, because on construction of the genesisDoc I want to have unique ownership of GenesisDoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do get it, it's just using non-pointer values is idiomatic way of doing this in go. If this is really such a special case that we need to be extra explicit about copying then maybe. But my concern is that fighting the language like this leads to a mess/a burden we cannot hope to (would not want to) live up to everywhere.

I particularly don't like this given that we are running it through go-wire for little reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not sure whether it is fighting the language or fighting bad habits

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using go-wire was here rather elegant; otherwise it requires many lines of reflecting which keytype it is then copying it in the correct fixed size byte array and then casting it back to the interface;

in my opinion interface PubKey should have a Clone() but it does not; so using the available interfaces worked quite nicely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it allows you to make it explicit when you're copying data; and as a result avoid copying it when you don't have to.

You are copying data exactly when you don't have to because PubKey.Bytes() does a copy itself (as it ought to)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it returns a []byte as type byte prepended public key bytes; I need to then copy that byte slice in a [32]byte or [64]byte and then cast that to the interface; this one line captures all that;

Im fine for it to be improved in eris-db/crypto; but right now I need a way to take deep ownership of the data in genesisDoc so that once the GenesisDoc is created it is independent of the memory that went into creating it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is you have a PubKey, you don't need a clone, it's the same PubKey genesisValidator.PubKey and the PubKey interface is immutable.

Copy link
Contributor

@silasdavis silasdavis Feb 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silasdavis silasdavis merged commit cc2ce6a into hyperledger-archives:release-0.16 Feb 22, 2017
@benjaminbollen
Copy link
Contributor Author

continued in #506

silasdavis added a commit to silasdavis/burrow that referenced this pull request Mar 9, 2019
…se-0.16-cutout-genesis

Release 0.16 - alignment with consolidated tooling wrt chain making
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging this pull request may close these issues.

2 participants